#pragma once

#include <vector>
#include <queue>
#include "Thread.hpp"
#include "Mutex.hpp"
#include <unistd.h>
#include <pthread.h>

namespace threadpool
{
    using namespace std;
    using namespace thread;
    using namespace mutex;

    template <class T>
    class threadPool;

    template <class T>
    class threadData/*传递给线程例程的参数*/
    {
    public:
        threadPool<T> *_this;
        string _name;
    };

    template <class T>
    class threadPool
    {
    private:
#define INIT_THREAD_NUM 10 /*默认线程数*/
        static void *start_routine(void *args)
        {
            threadData<T> *td = static_cast<threadData<T> *>(args);
            while (true)
            {
                T task;
                {
                    LockGuard lockguard(td->_this->mutex());
                    while (td->_this->isQueueEmpty())
                    { /*如果队列为空就说明没有任务，没有任务就去条件变量阻塞*/
                        td->_this->queueWait();
                    }
                    task = td->_this->taskPop();
                    td->_this->queueUnlock();
                }
                /*获取任务是互斥的，但是执行任务是并发的*/
                task();
            }
        }

    private:
        /*将一些操作封装起来*/
        void queueLock() { pthread_mutex_lock(&_mutex); }
        void queueUnlock() { pthread_mutex_unlock(&_mutex); }
        bool isQueueEmpty() { return _taskQueue.empty(); }
        void queueWait() { pthread_cond_wait(&_cond, &_mutex); }
        T taskPop()
        {
            T task = _taskQueue.front();
            _taskQueue.pop();
            return task;
        }
        pthread_mutex_t *mutex() { return &_mutex; }

    public:
        threadPool(int num = INIT_THREAD_NUM)
            : _threadVec(num)
        {
            pthread_mutex_init(&_mutex, nullptr);
            pthread_cond_init(&_cond, nullptr);
            for (int i = 0; i < _threadVec.size(); i++)
            {
                /*构造函数只负责创建线程对象
                 *参数的传递在start方法中*/
                _threadVec[i] = new Thread();
            }
        }

        ~threadPool()
        {
            pthread_mutex_destroy(&_mutex);
            pthread_cond_destroy(&_cond);
        }

        /*提供给外部的接口，外部调用start接口
         *就说明线程池启动，可以投递任务*/
        void start()
        {
            for (auto &e : _threadVec)
            {
                threadData<T> *td = new threadData<T>();
                td->_name = e->thread_name();
                td->_this = this;

                e->start(start_routine, td);
                cout << e->thread_name() << " start ..." << endl;
            }
        }

        /*向线程池当中添加任务*/
        void push(const T &in)
        {
            LockGuard lockguard(&_mutex);
            _taskQueue.push(in);
            pthread_cond_signal(&_cond);
        }

    private:
        /*vector:管理线程的数据结构
         *queue:管理任务的数据结构*/
        vector<Thread *> _threadVec;
        queue<T> _taskQueue;

        /*未来肯定是要访问队列的，所以队列是一个共享资源
         *那么就需要锁
         *如果线程没有拿到任务，那么就要去条件变量下阻塞*/
        pthread_mutex_t _mutex;
        pthread_cond_t _cond;
    };
} /*namespace threadpool ends here*/